home *** CD-ROM | disk | FTP | other *** search
- /*
- File: CFonts.cp
-
- Contains: Font manager wrapper classes
-
- Written by: Arno Gourdol
-
- Copyright: © 1994-1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <1> 3/31/96 arno First created.
-
- */
-
- #include "CFonts.h"
-
-
- #include "assert.h"
- #include "macros.h"
-
- #include "NeoTextBox.h"
-
-
- // ---------------------------------------------------------------------
- //
- // CFontSpec
- //
- // The CFontSpec class manages font information (script, font, size,
- // style). It caches the current font settings to avoids doing
- // uneccessary Toolbox calls. It also caches font metrics for the
- // same reason.
- //
- // A typical use is:
- /*
- CFontSpec saveFontSpec;
- CFontSpec smallFontSpec(smSystemScript, kSmallFont);
- CFontSpec systemFontSpec(smSystemScript, kSystemFont);
-
- saveFontSpec.Save(); // Saves the current font information
-
- // ... more inits
-
- systemFontSpec.DrawString("Hello"); // Use the system font
-
- //...
-
- smallFontSpec.DrawString("word"); // Use the small default font
-
- saveFontSpec.Restore(); // Restore the font information
-
- */
- //
- // ---------------------------------------------------------------------
-
-
-
- Boolean CFontSpec::pSystemFontInited = false;
- CFontSpec pSystemFontSpec; // should belong to CFontSpec as a static member but constructors
- // aren't called from CFM initialization
-
- Boolean CFontSpec::pSmallFontInited = false;
- CFontSpec pSmallFontSpec; // should belong to CFontSpec as a static member but constructors
- // aren't called from CFM initialization
-
- Handle CFontSpec::pItl0 = NULL;
- Handle CFontSpec::pItl1 = NULL;
- Handle CFontSpec::pItl2 = NULL;
-
- short CFontSpec::fFontToScriptCacheFont = 0;
- ScriptCode CFontSpec::fFontToScriptCacheScript = smSystemScript;
-
- ScriptCode CFontSpec::fSupportsCondenseCacheScript = smRoman;
- Boolean CFontSpec::fSupportsCondenseCache = true;
-
- ScriptCode CFontSpec::fScriptIsRTLCacheScript = smRoman;
- Boolean CFontSpec::fScriptIsRTLCache = false; // Roman is not right to left
-
- ScriptCode CFontSpec::fScriptFontCacheScript = smAllScripts;
- short CFontSpec::fScriptFontCacheFont = 1049;
- long CFontSpec::fScriptFontCacheFontAndSize = 0;
-
-
- //
- // CFontSpec::CFontSpec
- //
- //
-
- CFontSpec::CFontSpec(void) :
- fScript(smNoScript),
- fLineHeight(-10),
- fFont(-10),
- fStyle(normal),
- fMode(srcOr)
- {
- #ifndef NDEBUG
- fSaveCount = 0;
- #endif
-
- }
-
-
-
- //
- // CFontSpec::CFontSpec
- //
- //
-
- CFontSpec::CFontSpec(ScriptCode scriptCode,
- FontCode font) :
- fScript(smNoScript),
- fLineHeight(-10),
- fFont(-10),
- fStyle(normal),
- fMode(srcOr)
- {
- #ifndef NDEBUG
- fSaveCount = 0;
- #endif
-
- this->SetFont(scriptCode, font);
- }
-
-
-
- //
- // CFontSpec::~CFontSpec
- //
- // Check that the calls to Save and Restore were balanced
- //
-
- CFontSpec::~CFontSpec()
- {
- #ifndef NDEBUG
- assert(fSaveCount == 0);
- #endif
- }
-
-
-
- //
- // CFontSpec::FontToScript
- //
- //
-
- ScriptCode CFontSpec::FontToScript(short font)
- {
- if (font == fFontToScriptCacheFont)
- {
- return fFontToScriptCacheScript;
- }
- else
- {
- fFontToScriptCacheScript = font;
- return fFontToScriptCacheScript = ::FontToScript(font);
- }
- }
-
-
-
- //
- // CFontSpec::SupportCondense
- //
- //
-
- Boolean CFontSpec::SupportCondense(ScriptCode script)
- {
- if (script == fSupportsCondenseCacheScript)
- {
- return fSupportsCondenseCache;
- }
- else
- {
- fSupportsCondenseCacheScript = script;
- return fSupportsCondenseCache = ((::GetScriptVariable(script, smScriptValidStyles) & condense) != 0);
- }
- }
-
-
-
- //
- // CFontSpec::ScriptIsRTL
- //
- //
-
- Boolean CFontSpec::ScriptIsRTL(ScriptCode script)
- {
- if (script == fScriptIsRTLCacheScript)
- {
- return fScriptIsRTLCache;
- }
- else
- {
- fScriptIsRTLCacheScript = script;
- return fScriptIsRTLCache = (::GetScriptVariable(script, smScriptRight) != 0);
- }
- }
-
-
-
- //
- // CFontSpec::ScriptFont
- //
- //
-
- long CFontSpec::ScriptFont(ScriptCode script, short font)
- {
- if ((script == fScriptFontCacheScript) && (font == fScriptFontCacheFont))
- {
- return fScriptFontCacheFontAndSize;
- }
- else
- {
- fScriptFontCacheScript = script;
- fScriptFontCacheFont = font;
- return fScriptFontCacheFontAndSize = ::GetScriptVariable(script, font);
- }
- }
-
-
-
- //
- // CFontSpec::Save
- //
- // Store in the object the current values for the font
- //
-
- void CFontSpec::Save(void)
- {
- GrafPtr curPort;
- GetPort(&curPort);
-
- // Read the values directly from the port data structure
- // (berk)
- fFont = curPort->txFont;
- fScript = FontToScript(fFont);
- fSize = curPort->txSize;
- fStyle = curPort->txFace;
- fMode = curPort->txMode;
-
- fLineHeight = 0; // Mark the font info as invalid
-
- #ifndef NDEBUG
- // Track how many times save and restore are called
- fSaveCount++;
- #endif
-
- }
-
-
-
- //
- // CFontSpec::Restore
- //
- // Sets the current port font characteristics to those of the object,
- // presumably stored by an earlier call to Save
- //
-
- void CFontSpec::Restore()
- {
- Use();
-
- #ifndef NDEBUG
- // Track how many times save and restore are called
- fSaveCount--;
- #endif
-
- }
-
-
-
- //
- // CFontSpec::SetFont
- //
- //
-
- void CFontSpec::SetFont(ScriptCode scriptCode,
- FontCode font)
- {
- // Check that the script code is in a reasonable range
- // -2 is current script, -1 system script
- // we ignore -3 = all scripts
- // the last script, 32, is for uninterpreted symbols
- assert((scriptCode >= -2) && (scriptCode <= 32));
-
- assert((font == kMonospacedFont) ||
- (font == kPreferedFont) ||
- (font == kSmallFont) ||
- (font == kSystemFont) ||
- (font == kApplicationFont) ||
- (font == kHelpManagerFont));
-
- {
- long fontAndSize;
-
- // Ask the Script manager what the font really is
- fontAndSize = ScriptFont(scriptCode, font);
-
- // Set the font and size
- fFont = HighWord(fontAndSize);
- fSize = LowWord(fontAndSize);
-
- fScript = FontToScript(fFont);
- fStyle = normal;
- fRightToLeft = ScriptIsRTL(fScript);
- fLineHeight = 0; // Note that the font information will need to be updated
- }
- }
-
-
-
- //
- // CFontSpec::SetFont
- //
- // Set the font named.
- // Return true if the font was found, false otherwise
- // Use GetFont to get the name of the font that was substituted
- //
-
- Boolean CFontSpec::SetFont(ScriptCode scriptCode,
- ConstStr255Param fontName)
- {
- short font;
- Boolean result = true; // Assume success
-
- ::GetFNum(fontName, &font);
- SetFontID(font);
-
- if (font == 0)
- {
- // Either the font was not found or we asked for the
- // system font
- {
- Str255 systemFontName;
-
- ::GetFontName(0, systemFontName);
- result = EqualString(fontName, systemFontName, false, false);
- }
- if (result == false)
- {
- // We didn't ask for the system font, i.e.
- // the font was not found. Use the application font for the requested script
- SetFont(scriptCode, kApplicationFont);
- // ??? We could use a more elaborate substitution strategy
- }
- }
-
- return result;
- }
-
-
- //
- // CFontSpec::SetFontID
- //
- //
-
- void CFontSpec::SetFontID(short font)
- {
- if (fFont != font)
- {
- fFont = font;
- fScript = FontToScript(fFont);
-
- fLineHeight = 0; // Invalidate the font information
- }
- }
-
-
-
- //
- // CFontSpec::SetSize
- //
- //
-
- void CFontSpec::SetSize(short size)
- {
- if (fSize != size)
- {
- fSize = size;
-
- fLineHeight = 0; // Invalidate the font information
- }
- }
-
-
-
- //
- // CFontSpec::SetStyle
- //
- //
-
- void CFontSpec::SetStyle(short style)
- {
- if (fStyle != style)
- {
- // Check it's a valid style
- assert(style <= 128);
- assert((style & ::GetScriptVariable(fScript, smScriptValidStyles)) == style);
-
- fStyle = style;
-
- fLineHeight = 0; // Invalidate the font information
- }
- }
-
-
-
- //
- // CFontSpec::SetMode
- //
- //
-
- void CFontSpec::SetMode(short mode)
- {
- // When the mode is changed, it is not necessary to invalidate the font information
- fMode = mode;
- }
-
-
-
- //
- // CFontSpec::GetFontMetrics
- //
- //
-
- void CFontSpec::GetFontMetrics(short& lineHeight,
- short& ascent,
- short& descent)
- {
- // If the font info is not up to date...
- if (fLineHeight == 0)
- {
- // ... recalc it
- CFontSpec saveFont;
- saveFont.Save();
- FontInfo fi;
- Use(); // Set the port to use the font info
- ::GetFontInfo(&fi); // Get the font metrics
- saveFont.Restore();
- fAscent = fi.ascent;
- fDescent = fi.descent;
- fLineHeight = fi.ascent + fi.descent + fi.leading;
-
- assert(fLineHeight != 0);
- }
-
- // Return the values now stored in the cache
- lineHeight = fLineHeight;
- ascent = fAscent;
- descent = fDescent;
- }
-
-
-
- //
- // CFontSpec::TruncString
- //
- //
-
- void CFontSpec::TruncString(short width,
- Str255 string,
- TruncCode where)
- {
- Boolean supportCondense;
- assert(width > 0);
-
- supportCondense = SupportCondense(GetScriptCode());
-
- // if script supports condensed style, clear it
- if (supportCondense)
- SetStyle(GetStyle() & ~condense);
-
- CFontSpec saveFont;
- saveFont.Save();
- Use();
- if (StringWidth(string) > width)
- {
- // If script supports condensed style, use it
- if (supportCondense)
- {
- SetStyle(GetStyle() | condense);
- Use();
-
- // If failed to condense enough, truncate
- if (StringWidth(string) > width)
- ::TruncString(width, string, where);
- }
- else
- {
- ::TruncString(width, string, where);
- }
- }
- saveFont.Restore();
- }
-
-
-
- //
- // CFontSpec::MeasureString
- //
- //
-
- short CFontSpec::MeasureString(ConstStr255Param string) const
- {
- CFontSpec saveFont;
- saveFont.Save();
- Use();
- short width = StringWidth(string);
- saveFont.Restore();
- return width;
- }
-
-
-
- //
- // CFontSpec::DrawString
- //
- //
-
- void CFontSpec::DrawString(ConstStr255Param string) const
- {
- CFontSpec saveFont;
- saveFont.Save();
- Use();
- ::DrawString(string);
- saveFont.Restore();
- }
-
-
- //
- // CFontSpec::DrawText
- //
- //
-
- void CFontSpec::DrawText(ConstStr255Param string,
- const CRect& bounds,
- short align) const
- {
- if (string == NULL || string[0] == 0) return;
-
- CFontSpec saveFont;
- saveFont.Save();
- Use();
- short endY;
- short lhUsed;
- (void)NeoTextBox(&string[1], string[0], bounds, align, -1, &endY, &lhUsed);
- saveFont.Restore();
- }
-
-
-
- //
- // CFontSpec::TENew
- //
- //
-
- TEHandle CFontSpec::TENew(void) const
- {
- CFontSpec saveFont;
- saveFont.Save();
- Use();
- Rect r;
- SetRect(&r, 0, 0, 0, 0);
- TEHandle text = ::TENew(&r, &r);
- if (IsLeftToRight())
- TESetAlignment(teFlushLeft, text);
- else
- TESetAlignment(teFlushRight, text);
- saveFont.Restore();
- return text;
- }
-
-
-
- //
- // CFontSpec::Use
- //
- // Set the current port information to match the ones defined
- // in the object. If they are already matching, no call to the
- // Toolbox is made
- //
- //
-
- void CFontSpec::Use() const
- {
- assert(fScript != smNoScript);
-
- GrafPtr curPort;
- GetPort(&curPort);
-
- // Must set the font first, because if size = 0,
- // it's depending on the script of the font
-
- if (curPort->txFont != fFont)
- TextFont(fFont);
-
- if (curPort->txSize != fSize)
- TextSize(fSize);
-
- if (curPort->txFace != fStyle)
- TextFace(fStyle);
-
- if (curPort->txMode != fMode)
- TextMode(fMode);
- }
-
-
-
- void CFontSpec::SetPortFont(GrafPtr port) const
- {
- GrafPtr savePort;
-
- // Save the current port
- ::GetPort(&savePort);
-
- ::SetPort(port);
-
- // Must set the font first, because if size == 0,
- // it's depending on the script of the font
-
- if (port->txFont != fFont)
- ::TextFont(fFont);
-
- if (port->txSize != fSize)
- ::TextSize(fSize);
-
- if (port->txFace != fStyle)
- ::TextFace(fStyle);
-
- if (port->txMode != fMode)
- ::TextMode(fMode);
-
- // Restore the port
- ::SetPort(savePort);
- }
-
- const CFontSpec &CFontSpec::GetSystemFontSpec(void)
- {
- if (!pSystemFontInited)
- {
- pSystemFontSpec.SetFont(smSystemScript, kSystemFont);
- pSystemFontInited = true;
- }
- return pSystemFontSpec;
- }
-
-
- const CFontSpec &CFontSpec::GetSmallFontSpec(void)
- {
- if (!pSmallFontInited)
- {
- pSmallFontSpec.SetFont(smSystemScript, kSmallFont);
- pSmallFontInited = true;
- }
- return pSmallFontSpec;
- }
-
-
- Handle CFontSpec::GetIntlResource(short id)
- {
- Handle h = NULL;
- if (id == 0)
- {
- if (pItl0 == NULL)
- {
- h = FetchIntlResource(id);
- assert(h != NULL);
- HandToHand(&h);
- HNoPurge(h);
- pItl0 = h;
- }
- else
- {
- h = pItl0;
- }
- }
- else if (id == 1)
- {
- if (pItl1 == NULL)
- {
- h = FetchIntlResource(id);
- assert(h != NULL);
- HandToHand(&h);
- HNoPurge(h);
- pItl1 = h;
- }
- else
- {
- h = pItl1;
- }
- }
- else if (id == 2)
- {
- if (pItl2 == NULL)
- {
- h = FetchIntlResource(id);
- assert(h != NULL);
- HandToHand(&h);
- HNoPurge(h);
- pItl2 = h;
- }
- else
- {
- h = pItl2;
- }
- }
- else
- {
- h = FetchIntlResource(id);
- }
- return h;
- }
-
-
- Handle CFontSpec::FetchIntlResource(short id)
- {
- CFontSpec saveFont;
- saveFont.Save();
- GetSystemFontSpec().Use();
- Handle h = ::GetIntlResource(id);
- saveFont.Restore();
- return h;
- }
-